/*************************************************************/
//player is our standard player class....yeah. It has the movement and
//can print
//Tyler Wozniak & Andrew Hall
/*************************************************************/

#include "Player.h"
#include "GameManager.h"
#include <MMSystem.h>
#include <MMSystem.h>
#include <Windows.h>
#include <cstdlib>

//Default constructor
Player::Player(GameManager& game,string type): Unit() 
{
	xPos = 1;
	yPos = 1;
	gameRef = &game;
	tinyxml2::XMLDocument doc;
	doc.LoadFile("../Inits/Units.xml");
	if(!doc.ErrorID())
	{
		tinyxml2::XMLElement* playerEl = doc.FirstChildElement( "player" )->FirstChildElement(type.c_str());
		name = playerEl->Attribute("name");
		strength = playerEl->IntAttribute("strength");
		agility = playerEl->IntAttribute("agility");
		stamina = playerEl->IntAttribute("stamina");
		if(name.empty() || !strength || !agility || !stamina)
		{
			defaultInit();
		}
	}
	else
		defaultInit();
	health = maxHealth();
};

//Initializes the values to default values in the event of bad file read
void Player::defaultInit()
{
	cout << "Error reading player data. Loading default values..." << endl;
	system("pause");
	name = "Null Ptr";
	strength = 7;
	agility = 5;
	stamina = 11;
}

//Copy constructor
Player::Player( const Player& other )
{
	name = other.name;
	strength = other.strength;
	agility = other.agility;
	stamina = other.stamina;
	xPos = other.xPos;
	yPos = other.yPos;
}

//Copy assignment operator
Player Player::operator=( const Player& other )
{
	name = other.name;
	strength = other.strength;
	agility = other.agility;
	stamina = other.stamina;
	xPos = other.xPos;
	yPos = other.yPos;
	return *this;
}

//Deals damage to the enemy unit
void Player::attack(Unit* other)
{
	RandInRange rander;
	int hitNum = rander(getHit());
	int evaNum = rander(other->getEva());
	if(hitNum > evaNum)
	{
		int preMitigationDamage = strength + (rander(strength/2)); //Damage is dealt as strength + a random number <half strength
		int mitigation = rander(other->getSta()/2); //The enemy's stamina mitigates part
		int damage = preMitigationDamage - mitigation; //Total damage
		if(!other->takeDamage(damage))
		{
			gameRef->getCurrentDisplay()->addPlayerMessage("You hit the " + other->getName() + " for " + Display::intToString(damage) + " damage.");
		}
		else
		{
			gameRef->getCurrentDisplay()->addPlayerMessage("You hit the " + other->getName() + " for " + Display::intToString(damage) + " damage, and it dies!");
			gameRef->getCurrentMap()->killEnemy(static_cast<Enemy*>(other));
		}
	}
	else
		gameRef->getCurrentDisplay()->addPlayerMessage("You attack the " + other->getName() + " but you miss.");
}

//Put all of the Move functions in one region
//Because they are essentially identical.
//Determines the gridspace being moved onto
//and then checks what is there and reacts
//appropriately.
#pragma region Move Functions
void Player::moveW()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos,xPos - 1);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->xPos -= 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}

}

void Player::moveE()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos,xPos + 1);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->xPos += 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}
}

void Player::moveN()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos - 1,xPos);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->yPos -= 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}
}

void Player::moveS()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos + 1,xPos);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->yPos += 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}
}

void Player::moveNW()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos - 1,xPos - 1);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->yPos -= 1;
		this->xPos -= 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}
}

void Player::moveNE()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos - 1,xPos + 1);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->yPos -= 1;
		this->xPos += 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}
}

void Player::moveSW()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos + 1,xPos - 1);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->yPos += 1;
		this->xPos -= 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}
}

void Player::moveSE()
{
	int posIndex = gameRef->getCurrentMap()->checkPosition(yPos + 1,xPos + 1);
	if(posIndex >= 0)
	{
		attack(dynamic_cast<Unit*>(gameRef->getCurrentMap()->getEnemy(posIndex)));
	}
	else if(posIndex == -1)
	{
		this->yPos += 1;
		this->xPos += 1;
	}
	else
	{
		gameRef->getCurrentDisplay()->addPlayerMessage("That's a wall.");
		playRandSound();
	}
}
#pragma endregion

//Prints the player data
void Player::print( ostream& o ) const
{
	o << "Name: " << name << "\nHP: " << health << "\nPow: " << strength << "\nEff: " << agility << "\nMem: " << stamina;
}

//Destructor
Player::~Player()
{
}

//Takes in a character and moves accordingly
void Player::move( char inp )
{
	if(inp == 'r')
	{
		moveNW();
	}
	if(inp == 't')
	{
		moveN();
	}
	if(inp == 'y')
	{
		moveNE();
	}
	if(inp == 'f')
	{
		moveW();
	}
	if(inp == 'h')
	{
		moveE();
	}
	if(inp == 'v')
	{
		moveSW();
	}
	if(inp == 'g')
	{
		moveS();
	}
	if(inp == 'b')
	{
		moveSE();
	}
}

//Regen a portion of HP
void Player::regen()
{
	int amtToRegen;
	amtToRegen = (double(maxHealth()) * .02); //Regen 2% of max hp
	amtToRegen += (double(stamina) * .1); //And 1% of stamina
	if(amtToRegen < 1)
		amtToRegen = 1;
	health += amtToRegen;
	if(health > maxHealth())
		health = maxHealth();
}
